---
title: 'How to Migrate to v2 from v1'
---

# How to Migrate to v2 from v1

## Changes in v2

React 19 officially introduces the `use` hook to handle promises.
Valtio v1 internally handled promises, which is no longer recommended.
In Valtio v2, promises are not handled internally,
and developers should explicitly use the `use` hook to manage promises.

Note: If you are still using React 18, you can use [the `use` hook shim](https://github.com/dai-shi/react18-use).

Valtio v2 also introduces two subtle changes in its design choices:

First, the behavior of `proxy(obj)` has changed. In v1, it was a pure function and deeply copied `obj`. In v2, it is an impure function and deeply modifies `obj`. Generally, reusing `obj` is not recommended. Unless you reuse `obj`, nothing will break.

Second, the behavior of `useSnapshot()` has been altered. Although it is a subtle change, it is less optimized to ensure compatibility with `useMemo` and the upcoming React compiler. The change may lead to extra re-renders in some edge cases, but it might not be noticeable.

Other notable changes to keep things updated and fresh include:

- Removal of all deprecated features
- Requirement of React version 18 and above
- Requirement of TypeScript version 4.5 and above
- The build target updated to ES2018

## Migration for breaking changes

### Resolving promises

```js
// v1
import { proxy, useSnapshot } from 'valtio'

const state = proxy({ data: fetch(...).then((res) => res.json()) })

const Component = () => {
  const snap = useSnapshot(state)
  return <>{JSON.stringify(snap.data)}</>
}
```

```js
// v2
import { use } from 'react'
import { proxy, useSnapshot } from 'valtio'

const state = proxy({ data: fetch(...).then((res) => res.json()) })

const Component = () => {
  const snap = useSnapshot(state)
  return <>{JSON.stringify(use(snap.data))}</>
  // If `data` is not an object, you can directly embed it in JSX.
  // return <>{snap.data}</>
}
```

### Impure `proxy(obj)`

If you don't reuse the object you pass to the proxy, nothing will break.

```js
import { proxy } from 'valtio'

// This works in both v1 and v2
const state = proxy({ count: 1, obj: { text: 'hi' } })

// This works in both v1 and v2
state.obj = { text: 'hello' }
```

That's the recommended way to use `proxy`.

For some reason, if you reuse the object, you need to use `deepClone` explicitly in v2 to keep the same behavior as v1.

```js
// v1
import { proxy } from 'valtio'

const initialObj = { count: 1, obj: { text: 'hi' } }
const state = proxy(initialObj)
// and do something later with `initialObj`

const newObj = { text: 'hello' }
state.obj = newObj
// and do something later with `newObj`
```

```js
// v2
import { proxy } from 'valtio'
import { deepClone } from 'valtio/utils'

const initialObj = { count: 1, obj: { text: 'hi' } }
const state = proxy(deepClone(initialObj))
// and do something later with `initialObj`

const newObj = { text: 'hello' }
state.obj = deepClone(newObj)
// and do something later with `newObj`
```

### `useLayoutEffect` server warning

If you're using React 18 with SSR, add this conditional to prevent excessive warnings.

```js
import { snapshot, useSnapshot as useSnapshotOrig } from 'valtio'

const isSSR = typeof window === 'undefined'
export const useSnapshot = isSSR ? (p) => snapshot(p) : useSnapshotOrig

// render with `useSnapshot` as usual
```

## Links

- https://github.com/pmndrs/valtio/discussions/703
- https://github.com/pmndrs/valtio/pull/810
